/*
 * formulation.c
 *
 *  Created on: 30/12/2011
 *      Author: marcio
 */

#include "formulation.h"

CPXENVptr env;//ambiente do cplex
CPXLPptr prob;//problema inteiro
long** varToEdge;//mapeamento de variavel para aresta
long*** edgeToVar;//mapeamento de aresta para variavel
long var;//numero de variaveis;

extern long k;//o k da coloração
extern long* va;//a ordem dos vertices



/*Inicializa o ambiente*/
int init(){
	setAdjMatrix(getSharedGraph());
	var = 0;
	long i,l,j;

	//alocação de memoria pra edgeVar
	edgeToVar = malloc(sizeof(long**)*nverts());
	for(i = 0; i < nverts(); i++){
		edgeToVar[va[i]] = malloc(sizeof(long*)*nverts());
		for(j = i; j < nverts(); j++){
			edgeToVar[va[i]][va[j]] = malloc(sizeof(long)*k);
		}
	}

	//alocação de memoria para verToedge
	varToEdge = malloc(sizeof(long*)*nverts()*nverts()*k);
	for(i = 0; i < nverts()*nverts()*k; i++){
		varToEdge[i] = malloc(sizeof(long)*3);
	}

	for(i = 0; i < nverts(); i++){
		for(j = i; j < nverts(); j++){
			if(hasEdge(va[i], va[j]) || i == j){
				for(l = 0; l < k; l++){
					edgeToVar[va[i]][va[j]][l] = var;
					varToEdge[var][0] = va[i];
					varToEdge[var][1] = va[j];
					varToEdge[var][2] = l;
					var++;
					//printf("var = %d é referente a %d %d %d \n", var, va[i], va[j], l);
				}
			}
		}
	}

	int status;
	env = CPXopenCPLEX(&status);
	prob = CPXcreateprob(env, &status, "Formulação de k-col!!!");
	double obj[var];
	double lb[var];
	double ub[var];
	char type[var];
	for(i = 0; i < var; i++){
		obj[i] = varToEdge[i][1] == varToEdge[i][0]? 1.0 : 0.0;
		lb[i] = 0.0;
		ub[i] = 1.0;
		type[i] = 'C';
	}
	//cria as variavies
	CPXnewcols(env, prob, var, obj, lb, ub, type, NULL);
	//defini o sentindo da função objetivo
	CPXchgobjsen(env, prob, CPX_MIN);
	CPXchgprobtype(env, prob, 	CPXPROB_LP);
	return 0;
}

/*adiciona restrição na anti-vizinhança de v referente a u e w*/
int addEdgeConstrain(long v, long u, long w){
	setAdjMatrix(getSharedGraph());
	int l;
	for(l = 0; l < k; l++){
		double rhs[1] = {0.0};//lado direito da restriçao
		char sense[1] = {'L'};// sentido da restriçao
		int rmatbeg[3] = {0,3};
		int rmatind[3];
		rmatind[0] = edgeToVar[v][u][l];
		rmatind[1] = edgeToVar[v][w][l];
		rmatind[2] = edgeToVar[v][v][l];
		double rmatval[3] = {1.0, 1.0, -1.0};
		CPXaddrows(env, prob, 0, 1, 3, rhs, sense, rmatbeg, rmatind, rmatval, NULL, NULL);
	}
	return 0;
}

/*adiciona restrição de aresta a u e v*/
int addIndConstrain(long v, long u){
	setAdjMatrix(getSharedGraph());
	int l;
	for(l = 0; l < k; l++){
		double rhs[1] = {0.0};//lado direito da restriçao
		char sense[1] = {'L'};// sentido da restriçao
		int rmatbeg[2] = {0,2};
		int rmatind[2];
		rmatind[0] = edgeToVar[v][u][l];
		rmatind[1] = edgeToVar[v][v][l];
		double rmatval[2] = { 1.0, -1.0};
		CPXaddrows(env, prob, 0, 1, 2, rhs, sense, rmatbeg, rmatind, rmatval, NULL, NULL);
	}
	return 0;
}

/*Adiciona restrição de Cover referente a v*/
int addCoverConstrain(long v){
	setAdjMatrix(getSharedGraph());
	int i, l, num = 0;
	double rhs[1] = {k};//lado direito da restriçao
	char sense[1] = {'G'};// sentido da restriçao
	int rmatbeg[2];
	int rmatind[nverts()*k];
	double rmatval[nverts()*k];
	for(i = 0; i <= v; i++){
		if(hasEdge(va[v], va[i]) || i == v){
			for(l = 0; l < k; l++){
				rmatval[num] = 1.0;
				rmatind[num] = edgeToVar[va[i]][va[v]][l];
				num++;
			}
		}
	}
	rmatbeg[0] = 0;
	rmatbeg[1] = num;
	CPXaddrows(env, prob, 0, 1, num, rhs, sense, rmatbeg, rmatind, rmatval, NULL, NULL);
	return 0;
}

int deleteFormulation(){
	setAdjMatrix(getSharedGraph());
	int i, j;
	for(i = 0; i < nverts(); i++){
		for(j = 0; j < nverts(); j++){
			free(edgeToVar[i][j]);
		}
		free(edgeToVar[i]);
		free(varToEdge[i]);
	}
	free(edgeToVar);
	free(varToEdge);
	return 0;
}
